/**
 * 
 */
package idv.takeshi.software.productline.bookstore.presentation.web.controller;

import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import idv.takeshi.software.productline.bookstore.application.service.UserAccountAlreadyActivatedException;
import idv.takeshi.software.productline.bookstore.application.service.UserAccountNotFoundException;
import idv.takeshi.software.productline.bookstore.application.service.UserRegistrationSerivce;
import idv.takeshi.software.productline.bookstore.application.service.dto.IndividualAccountDto;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.Customer;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.IndividualAccount;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.RoleDuplicateException;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.UserAccountDuplicateException;
import idv.takeshi.software.productline.bookstore.domain.model.useraccount.UserAccountFactory;

import org.apache.commons.lang.Validate;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * A Controller for User Account registration.
 * @author takeshi
 *
 */
@Controller("userAccountRegistrationController")
@RequestMapping("/register")
public class UserAccountRegistrationController {
	
	private static final String USER_ACCOUNT_DTO_NAME = "userAccountDto";

	private static final Log log = LogFactory.getLog(UserAccountRegistrationController.class);
	
	private UserRegistrationSerivce inidividualAccountRegistrationSerivce;
	
	@Autowired
	private MessageSource messageSource;
	
	@Autowired
	private UserAccountFactory userAccountFactory;
	
	@RequestMapping(value = "/create.html", method = RequestMethod.GET)
	public void createUserAccountTdo(ModelMap modelMap){
		modelMap.put(USER_ACCOUNT_DTO_NAME, new IndividualAccountDto());
	}
	
	/**
	 * Register a new user customer account.
	 * @param userAccountDto
	 * @param result
	 * @param locale
	 * @param request
	 * @param modelMap 
	 * @return
	 * @throws UserAccountAlreadyActivatedException 
	 * @throws RoleDuplicateException 
	 */
	@RequestMapping(value = "/create.html", method = RequestMethod.POST)
	public String registerAUserAccount(
			@ModelAttribute(USER_ACCOUNT_DTO_NAME) @Valid final IndividualAccountDto individualAccountDto,
			final BindingResult result, final Locale locale, HttpServletRequest request, ModelMap modelMap) 
		throws UserAccountAlreadyActivatedException, RoleDuplicateException{
		
		log.debug("ServerName = " + request.getServerName());
		log.debug("ServerPort = " + request.getServerPort());
		log.debug("ContextPath = " + request.getContextPath());
		
		if(result.hasErrors()){
			return "/register/create";
		}
		
		if(!StringUtils.equals(individualAccountDto.getPassword(), 
				individualAccountDto.getConfirmedPassword())){
			result.addError(new FieldError(USER_ACCOUNT_DTO_NAME, "confirmedPassword", 
					messageSource.getMessage("Pattern.userAccountDto.confirmedPassword.notEquals", 
					null, locale)));
			return "/register/create";
		}
		
		IndividualAccount userAccount = individualAccountDto.createModel(userAccountFactory);
		try {
			userAccount.addRole(Customer.class);
			this.inidividualAccountRegistrationSerivce.addUserAccountAndSendMail(userAccount, locale, getHostUrl(request));
		} catch (UserAccountAlreadyActivatedException e) {
			log.error("userAccount shall not be activated at this step", e);
			throw e;
		} catch (UserAccountDuplicateException e) {
			result.addError(new FieldError(USER_ACCOUNT_DTO_NAME, 
					"accountName", messageSource.getMessage("Pattern.userAccountDto.accountName.duplicate", 
					new Object[]{userAccount.getAccountName()}, locale)));
			return "/register/create";
		} catch (RoleDuplicateException e) {
			log.error("userAccount shall not be customer role assigned at this step", e);
			throw e;
		}
		
		modelMap.put("accountName", userAccount.getAccountName());
		modelMap.put("emailAddress", userAccount.getEmailAddress());
		
		return "redirect:/register/success.html";
	}
	
	private static String getHostUrl(HttpServletRequest request){
		StringBuffer hostUrl = new StringBuffer();
		
		hostUrl.append(request.getServerName());
		hostUrl.append(":" + request.getServerPort());
		if(StringUtils.isNotBlank(request.getContextPath())){
			hostUrl.append("/" + request.getContextPath());
		}
		return hostUrl.toString();
	}
	
	@RequestMapping(value = "/activateUser.html", method = RequestMethod.GET)
	public void activateUserAccount(@RequestParam("activationKey") String activationKey, 
			@RequestParam("userAccountName") String userAccountName, ModelMap modelMap){
		Validate.notEmpty(activationKey, "activationKey shall always not be null/empty");
		Validate.notEmpty(userAccountName, "userAccountName shall always not be null/empty");
		try {
			this.inidividualAccountRegistrationSerivce.activateUserAccountByActivationKey(activationKey);
			IndividualAccount userAccount = (IndividualAccount) this.inidividualAccountRegistrationSerivce.
				getUserAccountByName(userAccountName);
			
			modelMap.put("lastName", userAccount.getLastName());
			modelMap.put("userAccountName", userAccount.getAccountName());
			modelMap.put("success", Boolean.TRUE);
		} catch (UserAccountNotFoundException e) {
			log.error("userAccount not found by activationKey:" + activationKey, e);
		}
	}

	/**
	 * @return the inidividualAccountRegistrationSerivce
	 */
	public UserRegistrationSerivce getInidividualAccountRegistrationSerivce() {
		return inidividualAccountRegistrationSerivce;
	}

	/**
	 * @param inidividualAccountRegistrationSerivce the inidividualAccountRegistrationSerivce to set
	 */
	public void setInidividualAccountRegistrationSerivce(
			UserRegistrationSerivce inidividualAccountRegistrationSerivce) {
		this.inidividualAccountRegistrationSerivce = inidividualAccountRegistrationSerivce;
	}

	/**
	 * @return the messageSource
	 */
	public MessageSource getMessageSource() {
		return messageSource;
	}

	/**
	 * @param messageSource the messageSource to set
	 */
	public void setMessageSource(MessageSource messageSource) {
		this.messageSource = messageSource;
	}

	/**
	 * @return the userAccountFactory
	 */
	public UserAccountFactory getUserAccountFactory() {
		return userAccountFactory;
	}

	/**
	 * @param userAccountFactory the userAccountFactory to set
	 */
	public void setUserAccountFactory(UserAccountFactory userAccountFactory) {
		this.userAccountFactory = userAccountFactory;
	}
	
	
}
